// busy-error-data模式的中间件
// 参考了redux-effects.bind
const TYPE = Symbol('BUSY_ERROR_DATA');

export default store => next => action => {
    if (action.type !== TYPE) {
        return next(action);
    }

    function maybeDispatch(action) {
        return action && store.dispatch(action);
    }

    const {cb, meta} = action.meta;
    if (action.payload) {
        // 先执行封装的action
        let result = maybeDispatch(action.payload);
        if (Array.isArray(result)) {
            result = Promise.all(result);
        } else result = Promise.resolve(result);
        return result.then(
            data => maybeDispatch(cb({
                busy: false,
                data,
                error: null
            }, {
                ...meta,
                done: true
            }))
        ).catch(
            error => maybeDispatch(cb({
                busy: false,
                data: null,
                error
            }, meta))
        );
    }
    return maybeDispatch(cb({
        busy: true,
        data: undefined,
        error: undefined
    }, meta));
};

export function bed(action, cb, meta) {
    return [{
        type: TYPE,
        payload: null,
        meta: {cb, meta}
    }, {
        type: TYPE,
        payload: action,
        meta: {cb, meta}
    }];
}

import u from 'updeep';

export const nullKey = '-';
export const dataKey = '_';
export const ignoreKey = '*';
export const stateKey = '$.state';
export const errorKey = '$.error';

/**
 * 通用的store状态修改方法（针对bed封装的action）
 * @param state 原始state
 * @param payload 动作数据
 * @param key 数据标识
 * @param id 规范化和新建用的数据主键（名称或方法）
 * @return {*}
 */
export function up(state, payload, key = dataKey, id) {
    const {busy, error, data} = payload;
    let result = state;
    if (busy) {
        result = u.updateIn(stateKey, {[key]: busy}, result);
    } else {
        result = u.updateIn(stateKey, u.omit(key), result);
    }
    if (error) {
        result = u.updateIn(errorKey, {[key]: error}, result);
    } else {
        result = u.updateIn(errorKey, u.omit(key), result);
    }
    if (key !== ignoreKey) {
        let getId = id;
        if (typeof id === 'string') {
            getId = x => x[id];
        }
        if (Array.isArray(data) && getId) {
            // 所有元素按id存放
            data.forEach(x => {
                result = u({
                    [getId(x)]: x
                }, result);
            });
            // 数组本身只存id
            result = u({
                [key]: data.map(getId)
            }, result);
        } else {
            if (key === nullKey && data && getId) {
                // 新建数据替换之前的空key
                const newKey = getId(data);
                if (newKey) {
                    key = newKey;
                } else {
                    return result;
                }
            }
            result = u({
                [key]: u.if(!!data, data)
            }, result);
        }
    }
    return result;
}

/**
 * 指定键值更新
 * @param key 键名
 * @param fromMeta 是否从metadata的属性里获取（此时的key是属性名）
 * @return {*}
 */
export function upKey(key, fromMeta) {
    if (fromMeta) {
        return (state, payload, meta) => up(state, payload, meta[key]);
    }
    return (state, payload) => up(state, payload, key);
}

/**
 * 新建操作处理封装（调用up）
 * @param state 原始state
 * @param payload 动作数据
 * @param id 数据主键
 * @return {*}
 */
export function create(state, payload, id) {
    return up(state, payload, nullKey, id);
}

import {compact} from 'lodash';


export function cKey(...args) {
    return compact(args).join('/');
}


// get方法对应的更新方法

/**
 * 简便更新
 * @param state 类型若为字符或函数则为自定id
 * @param payload
 * @param __key
 * @returns {*}
 */
export function get(state, payload, {key} = {}) {
    return up(state, payload, key);
}
